package ge.telasi.tasks.ui;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

/**
 * Preference management.
 *
 * @author dimitri
 */
public class PrefUtils {
    static private final int pieceLength = Preferences.MAX_VALUE_LENGTH * 3 / 4;

    static public void putBoolean( String key, boolean value ) {
        getPreferences().putBoolean( key, value );
    }

    static public boolean getBoolean( String key, boolean def ) {
        return getPreferences().getBoolean( key, def );
    }

    static public void putInt( String key, int value ) {
        getPreferences().putInt( key, value );
    }

    static public int getInt( String key, int def ) {
        return getPreferences().getInt( key, def );
    }

    static public void putString( String key, String txt ) {
        getPreferences().put( key, txt );
    }

    static public String getString( String key ) {
        return getPreferences().get( key, null );
    }

    static public void putObject( String key, Object o ) {
        try {
            Preferences prefs = getPreferences();
            byte raw[] = object2Bytes( o );
            byte[][] pieces = breakIntoPieces( raw );
            writePieces(prefs, key, pieces);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    static public Object getObject( String key ) {
        try {
            Preferences prefs = getPreferences();
            byte pieces[][] = readPieces( prefs, key );
            byte raw[] = combinePieces( pieces );
            Object o = bytes2Object( raw );
            return o;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    static private Preferences getPreferences() {
        return Preferences.userNodeForPackage(PrefUtils.class);
    }

    static private byte[] object2Bytes( Object o ) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream( baos );
        oos.writeObject( o );
        return baos.toByteArray();
    }

    static private byte[][] breakIntoPieces( byte raw[] ) {
        int numPieces = (raw.length + pieceLength - 1) / pieceLength;
        byte pieces[][] = new byte[numPieces][];
        for (int i=0; i<numPieces; ++i) {
            int startByte = i * pieceLength;
            int endByte = startByte + pieceLength;
            if (endByte > raw.length) endByte = raw.length;
            int length = endByte - startByte;
            pieces[i] = new byte[length];
            System.arraycopy( raw, startByte, pieces[i], 0, length );
        }
        return pieces;
    }

    static private void writePieces( Preferences prefs, String key, byte pieces[][] ) throws BackingStoreException {
        Preferences node = prefs.node( key );
        node.clear();
        for (int i=0; i<pieces.length; ++i) {
            node.putByteArray( ""+i, pieces[i] );
        }
    }

    static private byte[][] readPieces( Preferences prefs, String key ) throws BackingStoreException {
        Preferences node = prefs.node( key );
        String keys[] = node.keys();
        int numPieces = keys.length;
        byte pieces[][] = new byte[numPieces][];
        for (int i=0; i<numPieces; ++i) {
            pieces[i] = node.getByteArray( ""+i, null );
        }
        return pieces;
    }

    static private byte[] combinePieces( byte pieces[][] ) {
        int length = 0;
        for (int i=0; i<pieces.length; ++i) {
            length += pieces[i].length;
        }
        byte raw[] = new byte[length];
        int cursor = 0;
        for (int i=0; i<pieces.length; ++i) {
            System.arraycopy( pieces[i], 0, raw, cursor, pieces[i].length );
            cursor += pieces[i].length;
        }
        return raw;
    }

    static private Object bytes2Object( byte raw[] ) throws IOException, ClassNotFoundException {
        ByteArrayInputStream bais = new ByteArrayInputStream( raw );
        ObjectInputStream ois = new ObjectInputStream( bais );
        Object o = ois.readObject();
        return o;
    }

}
